<template>
    <!-- 图片上传对话框 -->
    <v-dialog v-model="dialogVisible" max-width="800px" persistent>
        <v-card>
            <v-card-title class="pa-4 bg-primary">
                <v-icon class="mr-2" color="white">mdi-cloud-upload</v-icon>
                <span class="text-white">{{ currentTitle }}</span>
            </v-card-title>

            <v-card-text class="pa-6">
                <div v-if="!originalImageUrl" class="upload-step">
                    <!-- 上传区域 -->
                    <div class="upload-area" :class="{ 'drag-over': isDragOver }" @click="triggerFileInput"
                        @drop="handleDrop" @dragover.prevent="isDragOver = true" @dragleave.prevent="isDragOver = false"
                        @dragenter.prevent>
                        <div class="upload-placeholder">
                            <v-icon size="64" color="grey-lighten-1">mdi-cloud-upload</v-icon>
                            <p class="text-h6 text-grey-lighten-1 mt-4">点击或拖拽上传图片</p>
                            <p class="text-body-2 text-grey-lighten-2">支持 JPG、PNG、GIF 格式，最大 {{ currentOptions.maxSize
                                }}MB</p>
                        </div>
                    </div>

                    <!-- 隐藏的文件输入 -->
                    <input ref="fileInput" type="file" accept="image/*" style="display: none"
                        @change="handleFileSelect" />
                </div>

                <div v-else class="edit-step">
                    <!-- 编辑区域 -->
                    <div class="editor-container">
                        <canvas ref="editorCanvas" class="editor-canvas" @mousedown="startCrop" @mousemove="updateCrop"
                            @mouseup="endCrop"></canvas>
                    </div>

                    <!-- 编辑控制 -->
                    <div class="editor-controls mt-4">
                        <v-row align="center">
                            <v-col cols="12" md="6">
                                <v-btn-toggle v-model="editMode" mandatory>
                                    <v-btn value="crop" size="small">
                                        <v-icon start>mdi-crop</v-icon>
                                        裁剪
                                    </v-btn>
                                    <v-btn value="resize" size="small">
                                        <v-icon start>mdi-resize</v-icon>
                                        调整大小
                                    </v-btn>
                                </v-btn-toggle>
                            </v-col>
                            <v-col cols="12" md="6" class="text-right">
                                <v-btn color="grey" variant="outlined" size="small" @click="resetImage">
                                    <v-icon start>mdi-refresh</v-icon>
                                    重新选择
                                </v-btn>
                            </v-col>
                        </v-row>
                    </div>

                    <!-- 预览区域 -->
                    <div v-if="previewUrl" class="preview-section mt-4">
                        <v-divider class="mb-4" />
                        <div class="text-subtitle-2 mb-2">预览效果：</div>
                        <div class="preview-container">
                            <img :src="previewUrl" alt="预览" class="preview-image" />
                        </div>
                    </div>
                </div>
            </v-card-text>

            <v-card-actions class="pa-4 bg-grey-lighten-5">
                <v-spacer />
                <v-btn color="grey-darken-1" variant="text" @click="close">
                    取消
                </v-btn>
                <v-btn v-if="originalImageUrl" color="primary" variant="flat" @click="confirmEdit">
                    确认使用
                </v-btn>
            </v-card-actions>
        </v-card>
    </v-dialog>
</template>

<script lang="ts" setup>
import { ref, computed, nextTick, onUnmounted, watch } from 'vue';

interface Options {
    width?: number;
    height?: number;
    maxSize?: number; // MB
    quality?: number; // 0-1
    outputFormat?: 'jpeg' | 'png' | 'webp';
    title?: string;
}

interface Result {
    file: File;
    url: string;
    blob: Blob;
}

const emit = defineEmits<{
    'success': [result: Result];
    'error': [message: string];
    'cancel': [];
}>();

// 默认配置
const defaultOptions: Required<Options> = {
    width: 200,
    height: 200,
    maxSize: 5,
    quality: 0.8,
    outputFormat: 'jpeg',
    title: '图片上传与编辑'
};

// 响应式数据
const dialogVisible = ref(false);
const fileInput = ref<HTMLInputElement>();
const editorCanvas = ref<HTMLCanvasElement>();
const previewUrl = ref('');
const originalImageUrl = ref('');
const isDragOver = ref(false);
const editMode = ref('crop');
const currentOptions = ref<Required<Options>>({ ...defaultOptions });

// 裁剪相关状态
const cropStart = ref({ x: 0, y: 0 });
const cropEnd = ref({ x: 0, y: 0 });
const isCropping = ref(false);
const originalImage = ref<HTMLImageElement | null>(null);

// 计算属性
const currentTitle = computed(() => currentOptions.value.title);

// 打开对话框的方法
function open(userOptions: Options = {}): Promise<Result> {
    return new Promise((resolve, reject) => {
        // 合并配置
        currentOptions.value = { ...defaultOptions, ...userOptions };

        // 重置状态
        resetState();

        // 设置事件监听
        const successHandler = (result: Result) => {
            resolve(result);
            cleanup();
        };

        const errorHandler = (message: string) => {
            reject(new Error(message));
            cleanup();
        };

        const cancelHandler = () => {
            reject(new Error('用户取消操作'));
            cleanup();
        };

        const cleanup = () => {
            emit('success', successHandler as any);
            emit('error', errorHandler as any);
            emit('cancel', cancelHandler as any);
        };

        // 临时监听事件
        const handleSuccess = (result: Result) => {
            resolve(result);
        };

        const handleError = (message: string) => {
            reject(new Error(message));
        };

        const handleCancel = () => {
            reject(new Error('用户取消操作'));
        };

        // 显示对话框
        dialogVisible.value = true;

        // 存储回调
        (window as any).__imageUploadResolve = handleSuccess;
        (window as any).__imageUploadReject = handleError;
        (window as any).__imageUploadCancel = handleCancel;
    });
}

// 重置状态
function resetState() {
    previewUrl.value = '';
    originalImageUrl.value = '';
    isDragOver.value = false;
    editMode.value = 'crop';
    cropStart.value = { x: 0, y: 0 };
    cropEnd.value = { x: 0, y: 0 };
    isCropping.value = false;
    originalImage.value = null;

    if (fileInput.value) {
        fileInput.value.value = '';
    }
}

// 关闭对话框
function close() {
    dialogVisible.value = false;
    if ((window as any).__imageUploadCancel) {
        (window as any).__imageUploadCancel();
    }
}

// 重新选择图片
function resetImage() {
    originalImageUrl.value = '';
    previewUrl.value = '';
    if (fileInput.value) {
        fileInput.value.value = '';
    }
}

// 触发文件选择
function triggerFileInput() {
    fileInput.value?.click();
}

// 处理文件选择
function handleFileSelect(event: Event) {
    const target = event.target as HTMLInputElement;
    const file = target.files?.[0];
    if (file) {
        handleFile(file);
    }
}

// 处理拖拽上传
function handleDrop(event: DragEvent) {
    event.preventDefault();
    isDragOver.value = false;

    const files = event.dataTransfer?.files;
    const file = files?.[0];
    if (file) {
        handleFile(file);
    }
}

// 处理文件
function handleFile(file: File) {
    // 验证文件类型
    if (!file.type.startsWith('image/')) {
        if ((window as any).__imageUploadReject) {
            (window as any).__imageUploadReject('请选择图片文件');
        }
        return;
    }

    // 验证文件大小
    if (file.size > currentOptions.value.maxSize * 1024 * 1024) {
        if ((window as any).__imageUploadReject) {
            (window as any).__imageUploadReject(`文件大小不能超过 ${currentOptions.value.maxSize}MB`);
        }
        return;
    }

    // 读取文件
    const reader = new FileReader();
    reader.onload = (e) => {
        const result = e.target?.result as string;
        originalImageUrl.value = result;
    };
    reader.readAsDataURL(file);
}

// 初始化编辑器
async function initEditor() {
    if (!editorCanvas.value || !originalImageUrl.value) return;

    const canvas = editorCanvas.value;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    // 创建图片对象
    const img = new Image();
    img.onload = () => {
        originalImage.value = img;

        // 设置画布尺寸
        const maxWidth = 600;
        const maxHeight = 400;
        let { width, height } = img;

        if (width > maxWidth || height > maxHeight) {
            const ratio = Math.min(maxWidth / width, maxHeight / height);
            width *= ratio;
            height *= ratio;
        }

        canvas.width = width;
        canvas.height = height;

        // 绘制图片
        ctx.drawImage(img, 0, 0, width, height);

        // 生成初始预览
        generatePreview();
    };
    img.src = originalImageUrl.value;
}

// 生成预览
function generatePreview() {
    const canvas = editorCanvas.value;
    if (!canvas) return;

    const resultCanvas = document.createElement('canvas');
    const ctx = resultCanvas.getContext('2d');
    if (!ctx) return;

    resultCanvas.width = currentOptions.value.width;
    resultCanvas.height = currentOptions.value.height;

    // 直接缩放到目标尺寸作为默认预览
    ctx.drawImage(canvas, 0, 0, currentOptions.value.width, currentOptions.value.height);

    previewUrl.value = resultCanvas.toDataURL(`image/${currentOptions.value.outputFormat}`, currentOptions.value.quality);
}

// 开始裁剪
function startCrop(event: MouseEvent) {
    if (editMode.value !== 'crop') return;

    const canvas = editorCanvas.value;
    if (!canvas) return;

    const rect = canvas.getBoundingClientRect();
    cropStart.value = {
        x: event.clientX - rect.left,
        y: event.clientY - rect.top
    };
    isCropping.value = true;
}

// 更新裁剪区域
function updateCrop(event: MouseEvent) {
    if (!isCropping.value || editMode.value !== 'crop') return;

    const canvas = editorCanvas.value;
    if (!canvas) return;

    const rect = canvas.getBoundingClientRect();
    cropEnd.value = {
        x: event.clientX - rect.left,
        y: event.clientY - rect.top
    };

    // 重绘画布和裁剪框
    redrawCanvas();
    // 更新预览
    updatePreview();
}

// 结束裁剪
function endCrop() {
    isCropping.value = false;
}

// 重绘画布
function redrawCanvas() {
    const canvas = editorCanvas.value;
    if (!canvas || !originalImage.value) return;

    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    // 清除画布
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // 重绘图片
    if (originalImage.value) {
        ctx.drawImage(originalImage.value, 0, 0, canvas.width, canvas.height);
    }

    // 绘制裁剪框
    if (isCropping.value && editMode.value === 'crop') {
        const { x: startX, y: startY } = cropStart.value;
        const { x: endX, y: endY } = cropEnd.value;

        ctx.strokeStyle = '#1976d2';
        ctx.lineWidth = 2;
        ctx.setLineDash([5, 5]);
        ctx.strokeRect(startX, startY, endX - startX, endY - startY);

        // 绘制半透明遮罩
        ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.clearRect(startX, startY, endX - startX, endY - startY);
    }
}

// 更新预览
function updatePreview() {
    const canvas = editorCanvas.value;
    if (!canvas) return;

    let resultCanvas: HTMLCanvasElement;

    if (editMode.value === 'crop' && Math.abs(cropEnd.value.x - cropStart.value.x) > 10) {
        // 裁剪模式
        resultCanvas = document.createElement('canvas');
        const ctx = resultCanvas.getContext('2d');
        if (!ctx) return;

        const cropWidth = Math.abs(cropEnd.value.x - cropStart.value.x);
        const cropHeight = Math.abs(cropEnd.value.y - cropStart.value.y);

        resultCanvas.width = currentOptions.value.width;
        resultCanvas.height = currentOptions.value.height;

        // 裁剪并缩放到目标尺寸
        ctx.drawImage(
            canvas,
            Math.min(cropStart.value.x, cropEnd.value.x),
            Math.min(cropStart.value.y, cropEnd.value.y),
            cropWidth,
            cropHeight,
            0,
            0,
            currentOptions.value.width,
            currentOptions.value.height
        );
    } else {
        // 调整尺寸模式
        resultCanvas = document.createElement('canvas');
        const ctx = resultCanvas.getContext('2d');
        if (!ctx) return;

        resultCanvas.width = currentOptions.value.width;
        resultCanvas.height = currentOptions.value.height;

        ctx.drawImage(canvas, 0, 0, currentOptions.value.width, currentOptions.value.height);
    }

    previewUrl.value = resultCanvas.toDataURL(`image/${currentOptions.value.outputFormat}`, currentOptions.value.quality);
}

// 确认编辑
function confirmEdit() {
    const canvas = editorCanvas.value;
    if (!canvas) return;

    let resultCanvas: HTMLCanvasElement;

    if (editMode.value === 'crop' && Math.abs(cropEnd.value.x - cropStart.value.x) > 10) {
        // 裁剪模式
        resultCanvas = document.createElement('canvas');
        const ctx = resultCanvas.getContext('2d');
        if (!ctx) return;

        const cropWidth = Math.abs(cropEnd.value.x - cropStart.value.x);
        const cropHeight = Math.abs(cropEnd.value.y - cropStart.value.y);

        resultCanvas.width = currentOptions.value.width;
        resultCanvas.height = currentOptions.value.height;

        // 裁剪并缩放到目标尺寸
        ctx.drawImage(
            canvas,
            Math.min(cropStart.value.x, cropEnd.value.x),
            Math.min(cropStart.value.y, cropEnd.value.y),
            cropWidth,
            cropHeight,
            0,
            0,
            currentOptions.value.width,
            currentOptions.value.height
        );
    } else {
        // 调整尺寸模式
        resultCanvas = document.createElement('canvas');
        const ctx = resultCanvas.getContext('2d');
        if (!ctx) return;

        resultCanvas.width = currentOptions.value.width;
        resultCanvas.height = currentOptions.value.height;

        ctx.drawImage(canvas, 0, 0, currentOptions.value.width, currentOptions.value.height);
    }

    // 转换为Blob
    resultCanvas.toBlob((blob: Blob | null) => {
        if (blob) {
            const url = URL.createObjectURL(blob);

            // 创建文件对象
            const file = new File([blob], `edited-image.${currentOptions.value.outputFormat}`, {
                type: `image/${currentOptions.value.outputFormat}`,
                lastModified: Date.now(),
            });

            // 返回结果
            const result = { file, url, blob };
            if ((window as any).__imageUploadResolve) {
                (window as any).__imageUploadResolve(result);
            }
            dialogVisible.value = false;
        }
    }, `image/${currentOptions.value.outputFormat}`, currentOptions.value.quality);
}

// 监听编辑器显示状态
watch(originalImageUrl, async (url) => {
    if (url) {
        await nextTick();
        await initEditor();
    }
});

// 监听编辑模式变化
watch(editMode, () => {
    if (originalImageUrl.value) {
        generatePreview();
    }
});

// 组件卸载时清理
onUnmounted(() => {
    if (previewUrl.value && previewUrl.value.startsWith('blob:')) {
        URL.revokeObjectURL(previewUrl.value);
    }
});

// 暴露方法
defineExpose({
    open
});
</script>

<style lang="scss" scoped>
.upload-step,
.edit-step {
    min-height: 400px;
}

.upload-area {
    border: 3px dashed #e0e0e0;
    border-radius: 12px;
    cursor: pointer;
    transition: all 0.3s ease;
    background-color: #fafafa;
    min-height: 300px;
    display: flex;
    align-items: center;
    justify-content: center;

    &:hover {
        border-color: #1976d2;
        background-color: #f5f5f5;
    }

    &.drag-over {
        border-color: #1976d2;
        background-color: #e3f2fd;
        transform: scale(1.02);
    }
}

.upload-placeholder {
    text-align: center;
    padding: 40px 20px;
}

.editor-container {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 300px;
    border: 1px solid #e0e0e0;
    border-radius: 8px;
    background-color: #fafafa;
}

.editor-canvas {
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    cursor: crosshair;
    max-width: 100%;
    max-height: 400px;
    background-color: white;
}

.editor-controls {
    padding: 16px;
    background-color: #f5f5f5;
    border-radius: 8px;
}

.preview-section {
    text-align: center;
}

.preview-container {
    display: inline-block;
    border: 2px solid #e0e0e0;
    border-radius: 8px;
    padding: 8px;
    background-color: white;
}

.preview-image {
    display: block;
    border-radius: 4px;
}
</style>